use core::{cell::RefCell, sync::atomic::AtomicUsize};

use alloc::{borrow::ToOwned, collections::LinkedList, sync::Arc};

use core::sync::atomic::Ordering;

use crate::{irq::{rt_hw_interrupt_disable, rt_hw_interrupt_enable}, println, rt_extern::RtErrCode, scheduler::{get_cur_thread, rt_schedule}, thread::*, timer::rt_timer_start};

use super::*;

const MAX_SEM_VALUE: usize = 1000;

// pub trait Semaphore {
//     fn create<'a>(name: &'a str, val: usize, flag: IpcFlag) -> Self;//创建

//     fn take(&mut self, time: usize) -> Result<(), RtErrCode>;

//     fn release(&mut self) -> Result<(), RtErrCode>;

//     fn delete(self);
// }

const fn ipc_flag() -> IpcFlag {
    IpcFlag::RtIpcFifo(
        LinkedList::new()
    )
}

pub const fn static_sem(name: &str, val: usize, max_val: usize) -> RtSem {
    RtSem {
        name: name,
        inner: AtomicUsize::new(val),
        max_val,
        ipc_flag: ipc_flag(),
        suspend_list: LinkedList::new(),
        highest_prio: RT_THREAD_PRIORITY_MAX
    }
}

pub struct RtSem<'a> {
    name: &'a str,
    inner: AtomicUsize,
    max_val: usize,
    highest_prio: usize, // 用于优先级翻转的情况，暂时不添加
    ipc_flag: IpcFlag,
    suspend_list: LinkedList<Arc<RefCell<Thread>>>,
}

impl <'a>Ipc for RtSem<'a>  {
    fn ipc_suspend(&mut self, thread: Arc<RefCell<Thread>>) {
        rt_thread_suspend(thread.clone()).unwrap_or(());

        match &mut self.ipc_flag {
            IpcFlag::RtIpcFifo(list) => {
                list.push_back(thread);
            },
            IpcFlag::RtIpcPrio(set) => {
                // 根据优先级来排序线程，暂不实现
            }
        }
    }

    fn ipc_list_resume(&mut self) {
        match &mut self.ipc_flag {
            IpcFlag::RtIpcFifo(list) => {
                let thread = list.pop_front().unwrap();
                //println!("thread {:?} resume!", thread);
                rt_thread_resume(thread);
            },
            IpcFlag::RtIpcPrio(_set) => {
                // 暂不实现
            }
        }
    }

    fn ipc_list_resume_all(&mut self) {
        match &mut self.ipc_flag {
            IpcFlag::RtIpcFifo(list) => {
                while let Some(thread) = list.pop_front() {
                    rt_thread_resume(thread);
                }
            }
            IpcFlag::RtIpcPrio(_set) => {}
        }
    }
}

impl <'a>RtSem<'a> {
    pub fn create(name: &'a str, val: usize, flag: IpcFlag, max_val: usize) -> Self {
        assert!(val < MAX_SEM_VALUE);

        RtSem {
            name,
            max_val,
            inner: AtomicUsize::new(val),
            ipc_flag: flag,
            highest_prio: RT_THREAD_PRIORITY_MAX,
            suspend_list: LinkedList::new(),
        }
    }

    pub fn take(&mut self, time: usize) -> Result<(), RtErrCode> {

        self.inner.fetch_sub(1, Ordering::SeqCst); 

        // 大于init说明溢出，需要阻塞
        if *self.inner.get_mut() > self.max_val { 
            
            if time == 0 {
                return Err(RtErrCode::RtEtimeout);
            } else {

                let thread = get_cur_thread().unwrap();

                thread.borrow_mut().set_err(Ok(()));

                let level =  unsafe {rt_hw_interrupt_disable()};

                if time > 0 {
                    let timer = thread.borrow_mut().timer.clone();
                    timer.borrow_mut().set_tick(time);

                    rt_timer_start(timer);
                }
                //println!("thread {:?} suspend!", thread);
                self.ipc_suspend(thread);

                unsafe { rt_hw_interrupt_enable(level) };

                rt_schedule();

                let thread = get_cur_thread().unwrap();
                
                return thread.borrow_mut().err();
            }
        }
        Ok(())
    }

    pub fn release(&mut self) -> Result<(), RtErrCode> {

        self.inner.fetch_add(1, Ordering::SeqCst);

        let inner = *self.inner.get_mut();

        if inner < MAX_SEM_VALUE && inner != 0 { 
            if inner > self.max_val {
                self.inner.fetch_add(1, Ordering::SeqCst);
                return Err(RtErrCode::RtEfull);
            }
        } else {
            self.ipc_list_resume();

            rt_schedule();
        }

        Ok(())

    }

    pub fn delete(mut self) {
        self.ipc_list_resume_all();

        drop(self);
    }
}
